package externaldata.passageTrainTheorique;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Vector;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

import externaldata.gare.Gare;


public class PassageTrainTheoriqueHelper {

	private static String urlApi = "http://ms.api.transilien.com/?action=VehicleJourneyList";
	private static String filtreGareApi = "&StopAreaExternalCode=";
	private static String filtreDateApi = "&Date=";
	private static String filtreReseauTransportApi = "&NetworkExternalCode=";
	private static String filtrePaginationApi = "&PagerIndex=";
	
	private static String[] idRERTab = {"dua801", "dua802", "dua803", "dua804", "dua805"};
	private static String[] idTransilienTab = {"dua850", "dua851", "dua852", "dua853", "dua854", "dua855"};
	
	
	
	public static List<PassageTrainTheorique> getProchainsPassages(List<Gare> gares, int nbJours) {
		List<Thread> threadGareListe = new ArrayList<Thread>();
		
		List<PassageTrainTheorique> listeCompletePTT = new Vector<PassageTrainTheorique>();
		
		
		
		Calendar cal = new GregorianCalendar();
		Date today = new Date();
		
		for (int i = 0; i < nbJours; i++) {
			cal.setTime(today);
			cal.add(Calendar.DATE, i);
			Date dateAVerifier = cal.getTime();
			
			
			//listeCompletePTT.addAll(getPassagesParDate(filtreGare, dateAVerifier));
			for (Gare gare : gares) {
				String filtreGare = filtreGareApi + gare.getDua();
				Thread th = new Thread(new ThreadPTTGare(listeCompletePTT, filtreGare, dateAVerifier));
				th.start();
				threadGareListe.add(th);
			}
			
			for (Thread th : threadGareListe) {
				try {
					th.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
		return listeCompletePTT;
	}
	
	// Visibilité package pour être accessible depuis les threads uniquement /!\
	static List<PassageTrainTheorique> getPassagesParDate(String filtreGare, Date dateAVerifier) {
		List<Thread> threadReseauListe = new ArrayList<Thread>();
		
		List<PassageTrainTheorique> listeJourPTT = new Vector<PassageTrainTheorique>();
		
		SimpleDateFormat formater = new SimpleDateFormat("yyyy|MM|dd");
		String filtreDate = filtreDateApi + formater.format(dateAVerifier);
		
		for (String idRER : idRERTab) {
			//listeJourPTT.addAll(getPassagesParDateEtReseau(filtreGare, filtreDate, idRER));
			Thread th = new Thread(new ThreadPTTReseau(listeJourPTT, filtreGare, filtreDate, idRER));
			th.start();
			threadReseauListe.add(th);
		}
		
		for (String idTransilien : idTransilienTab) {
			//listeJourPTT.addAll(getPassagesParDateEtReseau(filtreGare, filtreDate, idTransilien));
			Thread th = new Thread(new ThreadPTTReseau(listeJourPTT, filtreGare, filtreDate, idTransilien));
			th.start();
			threadReseauListe.add(th);
		}
		
		for (Thread th : threadReseauListe) {
			
			try {
				th.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		return listeJourPTT;
	}
	
	// Visibilité package pour être accessible depuis les threads uniquement /!\
	static List<PassageTrainTheorique> getPassagesParDateEtReseau(String filtreGare, String filtreDate, String idReseau) {
		List<PassageTrainTheorique> listeJourReseauPTT = new ArrayList<PassageTrainTheorique>();
		
		List<String> xmlListFromApi = new ArrayList<String>();
		
		String filtreReseau = filtreReseauTransportApi + idReseau;
		int pageIndex = 0;
		
		while (true) {
			String tmpXml = null;
			
			try {
				tmpXml = getXmlFromApi(new URL(urlApi + filtreGare + filtreDate + filtreReseau + filtrePaginationApi + pageIndex));
			} catch (MalformedURLException e) {
				e.printStackTrace();
				break;
			}
			
			if (tmpXml != null) {
				xmlListFromApi.add(tmpXml);
			
				PassageTrainTheoriquePaginationHandler paginationHandler = parseXmlForPagination(tmpXml);
				
				if (paginationHandler.isCompleted()) {
					pageIndex = paginationHandler.getResponseStartIndex() + paginationHandler.getResponseCount();
					if (paginationHandler.getTotalCount() == pageIndex)
						break;
				}
			}
		}
		
		for (String xml : xmlListFromApi) {
			listeJourReseauPTT.addAll(parseXml(xml));
		}
		
		return listeJourReseauPTT;
	}
	
	private static String getXmlFromApi(URL url) {
		
		if (url != null) {
			
			HttpURLConnection conn = null;
			
			try {
				conn = (HttpURLConnection) url.openConnection();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			if (conn != null) {
				
				try {
					conn.setRequestMethod("GET");
					conn.setRequestProperty("User-Agent", "Mozilla/5.0");
				} catch (ProtocolException e) {
					e.printStackTrace();
				}
				
				// Lecture de la réponse retournée par l'API
				int responseCode = 0;
				
				try {
					responseCode = conn.getResponseCode();
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				if (responseCode == 200) {
					
					BufferedReader bReader = null;
					StringBuilder xmlResult = new StringBuilder();
					
					try {
						bReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
						
						String inputLine;
						
						while ((inputLine = bReader.readLine()) != null) {
							xmlResult.append(inputLine);
						}
					} catch (IOException e) {
						e.printStackTrace();
					} finally {
						try {
							if (bReader != null)
								bReader.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					
					try {
						return xmlResult.toString();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
		
		return null;
	}
	
	private static List<PassageTrainTheorique> parseXml(String xml) {
		
		List<PassageTrainTheorique> resultats = new ArrayList<PassageTrainTheorique>();
		
		if (xml != null) {
			
			try {
				// Création d'un SAX parser standard
				SAXParser parser = SAXParserFactory.newInstance().newSAXParser();

				// Utilisation du handler personnalisé
				PassageTrainTheoriqueHandler handler = new PassageTrainTheoriqueHandler();
				
				// Création d'un Stream contenant le XML à parser
				InputStream xmlStream = new ByteArrayInputStream(xml.getBytes());
				
				// Parsing
				parser.parse(xmlStream, handler);
				
				// On retourne le résultat du parsing
				resultats.addAll(handler.getResultat());
	  
			} catch (ParserConfigurationException e) { 
				System.out.println("Erreur de configuration du parseur lors de l'appel à newSAXParser()"); 
			} catch (SAXException e) { 
				System.out.println("Erreur de parsing lors de l'appel à parse()"); 
			} catch (IOException e) { 
				System.out.println("Erreur d'entrée/sortie lors de l'appel à parse()"); 
			}
		}
		
		return resultats;
	}
	
	private static PassageTrainTheoriquePaginationHandler parseXmlForPagination(String xml) {
		
		PassageTrainTheoriquePaginationHandler handler = new PassageTrainTheoriquePaginationHandler();
		
		if (xml != null) {
			try {
				// Création d'un SAX parser standard
				SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
				
				// Création d'un Stream contenant le XML à parser
				InputStream xmlStream = new ByteArrayInputStream(xml.getBytes());
				
				// Parsing
				parser.parse(xmlStream, handler);
	  
			} catch (ParserConfigurationException e) { 
				System.out.println("Erreur de configuration du parseur lors de l'appel à newSAXParser()"); 
			} catch (SAXException e) { 
				System.out.println("Erreur de parsing lors de l'appel à parse()"); 
			} catch (IOException e) { 
				System.out.println("Erreur d'entrée/sortie lors de l'appel à parse()"); 
			}
		}
		
		return handler;
	}
}
